package relu.R.weeds;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import jfm.utils.*;


/** Class for use with rJava to analyse IFS data as transition matrices. 
 * 
 * The following example code shows how to setup a sorter with data and then 
 * how to collect transition points for Poa Annua
 * \verbatim 
 library(rJava)
initialize <- function(){
  .jinit() # this starts the JVM
  .jaddClassPath("/Users/cooke/Sources/EclipseWS/javawfm/jfm.jar")
  .jaddClassPath("/Users/cooke/Sources/EclipseWS/jrelu/jrelu.jar")
}

createSorter <- function(){
  ifssorter <- .jnew("relu/R/weeds/IFSSorter")
  .jcall(ifssorter,"V","initFromCSV","IFSweeds.csv")
  ifssorter
}
initialize()
ifssorter <- createSorter() 

m <- .jcall(ifssorter,"[[D","getTransitionMatrix","POAANN",as.integer(1),as.integer(2))
mx <- .jevalArray(m[[1]])
my <- .jevalArray(m[[2]])
plot(mx,my)

 \endverbatim 
 * */
public class IFSSorter {
	
	static int[] fromyears ={1992,1993,1994,1995,1996};// 1997 is the last yr
	static int[] allYears={1992,1993,1994,1995,1996,1997};
	// First int is year second is crop
	private Map<WeedSpecies,Map<Integer,Map<Integer,Map<PlotIdentifier,ArrayList<Double>>>>> data =
		new HashMap<WeedSpecies,Map<Integer,Map<Integer,Map<PlotIdentifier,ArrayList<Double>>>>>();
	
//	private boolean containsOneOf(Map<Integer,Map<PlotIdentifier,ArrayList<Double>>> y1data)
	
//	public double[] getDensityDistribution(String speciesId,double[] bins){
	public double[] getDensityDistribution(String speciesId){
		WeedSpecies sp=IFSSorter.stringToSpecies.get(speciesId);
		int[] counts=new int[sp.bins().length];
		JFMMath.intZero1(counts);
		Map<Integer,Map<Integer,Map<PlotIdentifier,ArrayList<Double>>>> spdata=data.get(sp);
		
		for(int yr:allYears){
			if ( spdata.containsKey(yr) ){
				Map<Integer,Map<PlotIdentifier,ArrayList<Double>>> yrdata=spdata.get(yr);
				for(Map<PlotIdentifier,ArrayList<Double>> cfdata:yrdata.values()){
					for(ArrayList<Double> ctdata:cfdata.values()){
						double dens=JFMMath.avArray(ctdata);
						int b=TransitionMatrix.getBin(dens, sp.bins());
						counts[b]++;
					}
				}
			}
		}
		double[] densities=JFMMath.pDistFromCounts(counts);
		return densities;
	}
	
	//ww1=1,ww2=2,sprcer=c(3,5),wbar=4,osr=c(6,7),peasbeans=c(8,9,10),sa=12,pots=13
	
	private int[] allCrops(){
		int[] rval = {1,2,3,4,5,6,7,8,9,10,12,13};
		return rval;
	}
	
	public double[][] getTransitions(String speciesId){
		return getTransitions(speciesId,allCrops(),allCrops());
	}
	
	public double[][] getTransitions(String speciesId,int[] c2){
	//	System.out.println("New way");
		return getTransitions(speciesId,allCrops(),c2);
	}
	
	/** Get all weed density transitions for a particular species going from one of 
	 * crops in the from crop group, c1 and to one of the crops in the to crop group, c2.
	 * @return An two column array where first column are weed densities in the from crop and 
	 * the second column are weed densities in the to crop */
	public double[][] getTransitions(String speciesId,int[] c1,int[] c2){
		ArrayList<Double> from=new ArrayList<Double>();
		ArrayList<Double> to=new ArrayList<Double>();

		WeedSpecies sp=IFSSorter.stringToSpecies.get(speciesId);		
//		System.out.println(sp);
//		System.out.println(c1[0]+" "+c1.length);
//		System.out.println(c2[0]+" "+c2.length);
		Map<Integer,Map<Integer,Map<PlotIdentifier,ArrayList<Double>>>> spdata=data.get(sp);
		int numPoints=0;
		for ( int interval=1; interval<3;interval++){
		for(int yr:fromyears){
			if ( spdata.containsKey(yr) && spdata.containsKey(yr+interval)){
//				Map<Integer,Map<PlotIdentifier,ArrayList>>
				Map<Integer,Map<PlotIdentifier,ArrayList<Double>>> y1data=spdata.get(yr);
				Map<Integer,Map<PlotIdentifier,ArrayList<Double>>> y2data=spdata.get(yr+1);	
				for(int crop1:c1){
					for(int crop2:c2){
						if ( y1data.containsKey(crop1) && y2data.containsKey(crop2)){					
							Map<PlotIdentifier,ArrayList<Double>> y1c1data=y1data.get(crop1);
							Map<PlotIdentifier,ArrayList<Double>> y2c2data=y2data.get(crop2);
							for(PlotIdentifier pi:y1c1data.keySet()){
								if ( y2c2data.containsKey(pi) ){
					// We have a data hit
									from.add(jfm.utils.JFMMath.avArray(y1c1data.get(pi)));
									to.add(jfm.utils.JFMMath.avArray(y2c2data.get(pi)));
//									System.out.println(jfm.utils.JFMMath.avArray(y2c2data.get(pi)));
									numPoints++;
								}
							}
						}
					}
				}
			}
		}
		}
		//	System.out.println(speciesId+" "+numPoints);
		double[][] m=new double[2][numPoints];
		for(int i=0;i<numPoints;i++){
			m[0][i]=from.get(i);
			m[1][i]=to.get(i);
		}
		
		return m;
	}
	
	
	
	public static IFSSorter fromCSV(String fileName){		
		IFSSorter theSorter=new IFSSorter();
		theSorter.initFromCSV(fileName);
		return theSorter;
	}
	public void initFromCSV(String fileName){
		final BufferedReader reader;
		try {
			reader=new BufferedReader(new FileReader(fileName));
			String nextLine=reader.readLine();
			nextLine=reader.readLine();
			int lineCount=1;
			while(nextLine!=null){
//				System.out.println(lineCount);
				lineCount++;
				if ( nextLine.contains("SITE")){
//					System.out.println(nextLine);
					nextLine=reader.readLine();
				} else {
					addDatum(nextLine);
					nextLine=reader.readLine();
				}
			}
			
		} catch (FileNotFoundException ex){
			throw new Error(ex.getMessage());
		} catch (IOException ex){
			throw new Error(ex.getMessage());
		}
	}
	

	public void addDatum(String line){
		String[] vals=line.split(",");
		for(int i=0;i<vals.length;i++){
			vals[i]=vals[i].trim();
			if ( vals[i].contentEquals(".")){
				vals[i]="0";
			}
		}
//		PlotIdentifier specialId = new PlotIdentifier(2,8,3);
		
		PlotIdentifier id=new PlotIdentifier(Integer.parseInt(vals[0]),Integer.parseInt(vals[1]),Integer.parseInt(vals[2]));
		int yr=Integer.parseInt(vals[3]);
		int system=Integer.parseInt(vals[4]);
		int crop=Integer.parseInt(vals[5]);
		int phase=Integer.parseInt(vals[6]);
		double dist=Double.parseDouble(vals[7]);
		int nextci=8;
		for(WeedSpecies sp:WeedSpecies.values()){
			if ( !data.containsKey(sp)){
				data.put(sp,new HashMap<Integer,Map<Integer,Map<PlotIdentifier,ArrayList<Double>>>>());
			}
			if ( !data.get(sp).containsKey(yr)){
				data.get(sp).put(yr, new HashMap<Integer,Map<PlotIdentifier,ArrayList<Double>>>());
			}
			if ( !data.get(sp).get(yr).containsKey(crop)){
				data.get(sp).get(yr).put(crop,new HashMap<PlotIdentifier,ArrayList<Double>>());
			}
			if ( !data.get(sp).get(yr).get(crop).containsKey(id)){
				data.get(sp).get(yr).get(crop).put(id, new ArrayList<Double>());
			}
			ArrayList<Double> dat=data.get(sp).get(yr).get(crop).get(id);
			dat.add(Double.parseDouble(vals[nextci]));
			nextci++;
//			if ( id.equals(specialId) && sp==WeedSpecies.ALOMYO ){
	//			System.out.println(" found it "+id.toString()+" : "+vals[nextci-1]);
		//	}
		}
	}
	
	/*
	public enum Species{
		AVEFAT,ALOMYO,BROCOM,
		BROSTE,BRANAP,CAPBP,CHEALB,CIRARV,MYOARV,GALAPA,LAMPUR,
		MATSPP, PAPRHO ,POAANN ,POLAVI ,POLCON ,SENVUL ,SINARV ,SONSPP ,STEMED ,
		VERPER ,VIOARV ,VICFAB ,VERHED ,GALTET ,SOLTUB ,VOLCER ,LOLPER ,AGRREP,
		OTHSPP ,TOTNOWD ,TOTNOSP;
	}*/
	
//	public static Map<String,Species> stringToSpecies =new HashMap<String,Species>();
	public static Map<String,WeedSpecies> stringToSpecies =new HashMap<String,WeedSpecies>();
	static {
		for(WeedSpecies sp:WeedSpecies.values()){
			stringToSpecies.put(sp.toString(), sp);
		}
	}
	
	public double[] getSpeciesBins(String speciesId){
		WeedSpecies sp=IFSSorter.stringToSpecies.get(speciesId);
	//	System.out.println(sp+" "+sp.bins());
		return sp.bins();
	}
	
	private final class PlotIdentifier {
		public final int Field;
		public final int PlotNo;
		public final int Site;
		public PlotIdentifier(int s,int f,int  pn){
			Field=f;PlotNo=pn;Site=s;
		}
		

		public boolean equals(Object other){
			if ( this == other ){ return true;};
			if ( other instanceof PlotIdentifier){
				PlotIdentifier oth=(PlotIdentifier)other;
				if ( oth.Field==this.Field && oth.PlotNo==this.PlotNo && oth.Site == this.Site){
					return true;
				} 
			}
			return false;
		}
		public int hashCode(){
			int hash=7;
			hash=31*hash+Field;
			hash=31*hash+PlotNo;
			hash=31*hash+Site;
			return hash;
		}
		
		public String toString(){
			String str = new String(Site + " "+Field+" "+PlotNo);			
			return str;
		}
		
	}
	
	
}
